package towerDefense.screens;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import javax.imageio.ImageIO;
import towerDefense.TowerDefense;
import towerDefense.circlesprites.CircleSpriteGroup;
import towerDefense.circlesprites.CircleSpriteToSpriteCollisionGroup;
import towerDefense.libraries.TDLibraries;
import towerDefense.maps.TDTiledMap;
import towerDefense.towers.TargetableSprite;
import towerDefense.towers.TargettingSprite;
import towerDefense.towers.TowerSprite;
import towerDefense.towers.TowerSpriteGroup;
import towerDefense.units.ValuedSprite;
import towerDefense.util.TDException;
import util.BufferedImageModifier;
import com.golden.gamedev.GameEngine;
import com.golden.gamedev.GameObject;
import com.golden.gamedev.object.GameFont;
import com.golden.gamedev.object.PlayField;
import com.golden.gamedev.object.Sprite;
import com.golden.gamedev.object.SpriteGroup;
import com.golden.gamedev.object.Timer;
import com.golden.gamedev.object.collision.BasicCollisionGroup;


public class PlayScreen extends GameObject
{

//////////////////////////////////////////////////////////////////
////////////////////////// GAME SKELETON /////////////////////////
//////////////////////////////////////////////////////////////////

    TDTiledMap myMap;
    Sprite TileChecker;
    BufferedImage occupied;
    BufferedImage unoccupied;
    String myTowerToBuildID;
    String ElementalIDString;
    CircleSpriteGroup TOWERS;
    SpriteGroup PROJECTILES, UNITS;
    CircleSpriteToSpriteCollisionGroup TOWER_TARGETTING;
    BasicCollisionGroup PROJECTILE_UNITS;
    PlayField PLAYFIELD;
    LinkedList<Point2D> myPath;
    GameFont FONT1;
    Timer NEXTWAVE = new Timer(15000), DIFFICULTY_INCREASE = new Timer(75000),
            RATE = new Timer(1500);

    boolean amPlacingTower;
    private ValuedSprite CURRENT_LEVEL_SPRITE;
    private ArrayList<TargetableSprite> PLAYER_TARGETS;
    public static int RESOURCE_TALLY;
    /////////Constants for a default board////////////
    public static int LIFE_COUNT, LEVEL;

    public static final Dimension DEFAULT_TILE_DIM = new Dimension(64, 64);
    public static final File DEFAULT_BLUEPRINT =
        new File("src/maps/packages/basicGrass/");
    private static final String TILESTATE_DIRECTORY = "src/images/tilestate/";


    public PlayScreen (GameEngine ge)
    {
        super(ge);
    }


    @Override
    public void initResources ()
    {

        switch (TowerDefense.ELEMENT_TYPE)
        {
            case TowerDefense.EARTH_ID:
                myTowerToBuildID = "earth";
                ElementalIDString = "EARTH";
                break;
            case TowerDefense.FIRE_ID:
                ElementalIDString = "FIRE";
                myTowerToBuildID = "fire";
                break;
            case TowerDefense.WATER_ID:
                ElementalIDString = "WATER";
                myTowerToBuildID = "waterzebra";
                break;
            case TowerDefense.WIND_ID:
                ElementalIDString = "WIND";
                myTowerToBuildID = "windcow";
                break;
        }
        amPlacingTower = true;

        ///////////////////////////Build Font, counters

        //initialize sprite groups
        PROJECTILES = new SpriteGroup("Projectiles");
        TOWERS = new TowerSpriteGroup("PlacedTowers", PROJECTILES);
        UNITS = new SpriteGroup("Projectiles");
        PLAYER_TARGETS = new ArrayList<TargetableSprite>();
        RESOURCE_TALLY = 100;
        LIFE_COUNT = 50;
        LEVEL = 0;

        myMap =
            new TDTiledMap(new Dimension(this.getWidth(), this.getHeight()),
                           DEFAULT_BLUEPRINT);
        TDLibraries.CreateAllLibraries(myMap.getTileDim());
        myPath = myMap.createMapPath();
        try
        {

            occupied =
                BufferedImageModifier.getScaledInstance(ImageIO.read(new File(TILESTATE_DIRECTORY +
                                                                              "occupied.png")),
                                                        myMap.getTileDim().width,
                                                        myMap.getTileDim().height);
            unoccupied =
                BufferedImageModifier.getScaledInstance(ImageIO.read(new File(TILESTATE_DIRECTORY +
                                                                              "unoccupied.png")),
                                                        myMap.getTileDim().width,
                                                        myMap.getTileDim().height);
            TileChecker = new Sprite(unoccupied);

            TileChecker.setActive(false);
            TileChecker.setImmutable(true);
            FONT1 =
                fontManager.getFont(ImageIO.read(new File("src/images/fonts/BitmapFont.png")));
            ;

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        ////////////////////initialize Collision sets/////////////////////////////////
        TOWER_TARGETTING = new CircleSpriteToSpriteCollisionGroup()
        {

            @Override
            public void collided (Sprite s1, Sprite s2)
            {
                if (((TowerSprite) s1).getTarget() == null)
                {
                    ((TowerSprite) s1).setTarget(s2);
                }

            }
        };

        ////////add everything to the playfield
        PLAYFIELD = new PlayField(myMap);
        PLAYFIELD.addGroup(TOWERS);
        PLAYFIELD.addGroup(UNITS);
        PLAYFIELD.addGroup(PROJECTILES);
        PLAYFIELD.addCollisionGroup(TOWERS, UNITS, TOWER_TARGETTING);

    }


    @Override
    public void render (Graphics2D g)
    {

        PLAYFIELD.render(g);
        if (amPlacingTower)
        {
            TileChecker.render(g);
            FONT1.drawString(g,
                             ElementalIDString.toString(),
                             getMouseX() - 20,
                             getMouseY() - 20);
            FONT1.drawString(g,
                             "COST: " +
                                     TDLibraries.TowerLibrary.checkTowerByName(myTowerToBuildID)
                                                             .getCost(),
                             getMouseX() - 20,
                             getMouseY());
        }
        FONT1.drawString(g,
                         "RESOURCES: " + String.valueOf(RESOURCE_TALLY),
                         4,
                         12);
        FONT1.drawString(g, "LIVES: " + String.valueOf(LIFE_COUNT), 4, 30);
        FONT1.drawString(g,
                         "TIME UNTIL NEXT WAVE: " +
                                 (int) ((NEXTWAVE.getDelay() - NEXTWAVE.getCurrentTick()) / 1000),
                         300,
                         12);
        FONT1.drawString(g, "CURRENT LEVEL: " + LEVEL, 700, 12);

        FONT1.drawString(g,
                         "TOGGLE TOWER TYPE USING 1-4 KEYS",
                         TowerDefense.DEFAULT_DIM.width - 420,
                         TowerDefense.DEFAULT_DIM.height - 18);
        FONT1.drawString(g,
                         "TOGGLE BUILDMODE USING B-KEY",
                         TowerDefense.DEFAULT_DIM.width - 360,
                         TowerDefense.DEFAULT_DIM.height - 36);

        if (LIFE_COUNT <= 0)
        {
            FONT1.drawString(g,
                             "PRESS ESC TO RETURN TO MAIN MENU",
                             TowerDefense.DEFAULT_DIM.width / 2 - 200,
                             TowerDefense.DEFAULT_DIM.height / 2 - 6);
        }

    }


    @Override
    public void update (long elapsed)
    {
        if (LIFE_COUNT > 0)
        {
            PLAYFIELD.update(elapsed);
        }
        switch (bsInput.getKeyPressed())
        {
            case KeyEvent.VK_ESCAPE:
                parent.nextGameID = TowerDefense.MAIN_MENU;
                finish();
                break;
            //temp hotkeys
            case KeyEvent.VK_B:
                amPlacingTower = (!amPlacingTower);
                TileChecker.setActive(!TileChecker.isActive());
                break;
            case KeyEvent.VK_R:
                UNITS.add(cloneSprite(TDLibraries.UnitLibrary.getRandomUnit()));
                break;
            case KeyEvent.VK_M:
                RESOURCE_TALLY += 50;
                break;
            case KeyEvent.VK_1:
                myTowerToBuildID = "earth";
                ElementalIDString = "EARTH";
                break;
            case KeyEvent.VK_2:
                myTowerToBuildID = "fire";
                ElementalIDString = "FIRE";
                break;
            case KeyEvent.VK_3:
                myTowerToBuildID = "waterzebra";
                ElementalIDString = "WATER";
                break;
            case KeyEvent.VK_4:
                myTowerToBuildID = "windcow";
                ElementalIDString = "AIR";
                break;
            case KeyEvent.VK_5:
                myTowerToBuildID = "easterBunny";
                ElementalIDString = "?????";
                break;
            case KeyEvent.VK_PLUS:
                LIFE_COUNT++;break;
            case KeyEvent.VK_MINUS:
                LIFE_COUNT--;break;
            case KeyEvent.VK_K:
                UNITS.reset();
                break;

        }

        ////////////Performs occupied test while placing tower
        if (amPlacingTower)
        {
            TileChecker.setActive(true);
            TileChecker.setLocation(myMap.getTileWidth() *
                                            myMap.convertToTileX(getMouseX()),
                                    myMap.getTileHeight() *
                                            myMap.convertToTileY(getMouseY()));
            if (myMap.isOccupied(getMouseX() / myMap.getTileWidth(),
                                 getMouseY() / myMap.getTileHeight()) ||
                TDLibraries.TowerLibrary.checkTowerByName(myTowerToBuildID)
                                        .getCost() > RESOURCE_TALLY)
            {
                TileChecker.setImage(occupied);
            }
            else
            {
                TileChecker.setImage(unoccupied);
                if (this.click())
                {
                    placeTower(myTowerToBuildID);
                    TileChecker.setActive(false);
                }
            }
        }

        if (LIFE_COUNT <= 0)
        {
            PLAYFIELD.clearPlayField();
            parent.nextGameID = TowerDefense.MAIN_MENU;
            RATE.setActive(false);
            DIFFICULTY_INCREASE.setActive(false);
            NEXTWAVE.setActive(false);
        }
        else
        {

            if (DIFFICULTY_INCREASE.action(elapsed))
            {
                LEVEL++;
                RATE.setDelay((long) (RATE.getDelay() / 1.1));
                TDLibraries.UnitLibrary.increaseAllMaxHP(1.1, 500);
                DIFFICULTY_INCREASE.refresh();
            }

            if (NEXTWAVE.action(elapsed))
            {
                if (CURRENT_LEVEL_SPRITE == null) DIFFICULTY_INCREASE.refresh();
                CURRENT_LEVEL_SPRITE = TDLibraries.UnitLibrary.getRandomUnit();
                NEXTWAVE.refresh();
            }

            if (RATE.action(elapsed) && CURRENT_LEVEL_SPRITE != null)
            {
                UNITS.add(cloneSprite(CURRENT_LEVEL_SPRITE));
            }

            if (!amPlacingTower)
            {
                if (this.click())
                {
                    for (Sprite s : TOWERS.getSprites())
                    {
                        if (s == null){

                            detargetSprites();
                            PLAYER_TARGETS.clear();
                            break;
                        }
                        else if (s != null)
                        {
                            if (tryTargetting(s))
                            {
                                if (bsInput.isKeyDown(KeyEvent.VK_SHIFT));
                                        //do nothing
                                else 
                                    PLAYER_TARGETS.clear();
                                ((TargetableSprite) s).setTargetted(true);
                                PLAYER_TARGETS.add((TargetableSprite) s);
                                break;
                            }
                        }
                        
                    }
                    
                }
                else if (rightClick())
                {
                    for (Sprite s : UNITS.getSprites())
                    {
                        if (s != null)
                        {
                            if (tryTargetting(s))
                            {
                                for (Sprite t : PLAYER_TARGETS)
                                {
                                    ((TargettingSprite) t).setTarget(s);
                                    break;
                                }

                            }
                        }
                    }
                }
            }
        }

    }


    private void detargetSprites ()
    {

        for (TargetableSprite s: PLAYER_TARGETS){
            s.setTargetted(false);
        }
    }


    private boolean tryTargetting (Sprite s)
    {

        if (getMouseX() > s.getX() && getMouseX() < (s.getX() + s.getWidth()) &&
            getMouseY() > s.getY() && getMouseY() < (s.getY() + s.getHeight())) return true;
        return false;
    }


    /**
     * @param s
     * @return
     * @throws CloneNotSupportedException
     */
    private ValuedSprite cloneSprite (ValuedSprite s)
    {
        try
        {
            ValuedSprite vs = (ValuedSprite) s.clone();
            vs.setLocation(myPath.getFirst().getX() - s.getWidth() / 2,
                           myPath.getFirst().getY() - s.getHeight() / 2);
            vs.setPath((LinkedList<Point2D>) myPath.clone());
            return vs;
        }
        catch (Exception e)
        {
            throw new TDException("Clone issues");
        }
    }


    private void placeTower (String towerID)
    {
        TowerSprite t = TDLibraries.TowerLibrary.createTowerByName(towerID);
        myMap.setOccupied(myMap.convertToTileX(getMouseX()),
                          myMap.convertToTileY(getMouseY()),
                          true);
        t.setLocation(myMap.getTileWidth() * myMap.convertToTileX(getMouseX()),
                      myMap.getTileHeight() * myMap.convertToTileY(getMouseY()));
        TOWERS.add(t);
        RESOURCE_TALLY -= t.getCost();
    }
//        
}

//    /**
//     * @return 
//     * @throws IOException
//     */
//    private ValuedSprite createtestunit () throws IOException
//    {
//        LinkedList<Point2D> path = new LinkedList<Point2D>();
//        path.addAll(Arrays.asList(new Point2D[] {new Point2D.Double(25,25), new Point2D.Double(500,500), new Point2D.Double(25,25)}));
//        return new ValuedSprite( BufferedImageModifier.getScaledInstance(ImageIO.read(new File("src/images/units/tuck.png")), 50, 50),
//                                   1000,
//                                   1000,
//                                   50,
//                                   .5,
//                                   path,
//                                   1000);
//    }

